#ifndef _CROSS_BOX_H_JM_20120624
#define _CROSS_BOX_H_JM_20120624

#include <iostream>
#include "../runtime/AutomaticBoxCreatorRegistration.h"
#include "RootBox.h"

namespace jm4bbx {

	struct CrossBoxDescriptor {
		//static const char* BOX_ID;
		static const char* FORK_RATIO_PARAMETER_NAME;
		static const char* DESTINATIONS_PARAMETER_NAME;
		static const int INPUT_GROUP_INDEX = 0;
		static const int OUTPUT_GROUP_START_INDEX = 1;
	};

	class CrossBox : public Box/*<CrossBoxDescriptor>*/ {
	public:
		typedef CrossBoxDescriptor BoxIO;


		CrossBox(bobox::box_id_type id, bobox::box_tid_type tid, bobox::request *req, 
			const bobox::parameters &params) 
			: Box(id, tid, req, params)
			, forkFactor_(1)
			, destinations_(1)
			, servedDestinations_(0)
		{


			if (params.has_parameter(BoxIO::FORK_RATIO_PARAMETER_NAME)) {
				params.get_parameter(BoxIO::FORK_RATIO_PARAMETER_NAME, forkFactor_);
			}
			if (params.has_parameter(BoxIO::DESTINATIONS_PARAMETER_NAME)) {
				params.get_parameter(BoxIO::DESTINATIONS_PARAMETER_NAME, destinations_);
			}

			assert(forkFactor_ > 0);
			assert(destinations_ > 0);
		} 

		virtual void initImpl() {
			// Input
			add_group(group_index_type(BoxIO::INPUT_GROUP_INDEX), columnType(0), 0);
			// Output
			for (size_t i = 0; i <= destinations_; ++i) {
				add_group(group_index_type(BoxIO::OUTPUT_GROUP_START_INDEX + i), 
					columnType(0), 0);
			}	
			// Cakanie na vstup
			receive(inType(0), group_index_type(BoxIO::INPUT_GROUP_INDEX));
		}

		virtual void sync_mach_etwas() {

			if (servedDestinations_ + destinations_ >= forkFactor_) {
				for (size_t i = 0; i < destinations_; ++i) {
					send_poisoned(bobox::outarc_index_type(BoxIO::OUTPUT_GROUP_START_INDEX + i));
				}
				std::cout << "Fork END" << std::endl;
				servedDestinations_ += destinations_;
				receive(inType(0), group_index_type(BoxIO::INPUT_GROUP_INDEX));
			}
			else {
				for (size_t i = 0; i < destinations_; ++i) {
					send(bobox::outarc_index_type(BoxIO::OUTPUT_GROUP_START_INDEX + i),
						group_index_type(BoxIO::OUTPUT_GROUP_START_INDEX + i));
				}
				std::cout << "Fork" << std::endl;
				servedDestinations_ += destinations_;
			}
		}

	protected:

	private:
		int forkFactor_;
		int destinations_;	
		int servedDestinations_;
	};
} // namespace jm4bbx

#endif
